package org.stvd.common.security.filter;

import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.MDC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.stvd.common.Consts;
import org.stvd.core.util.json.JsonUtils;
import org.stvd.core.web.IPUtil;
import org.stvd.core.web.URLUtil;
import org.stvd.entities.admin.Users;
import org.stvd.service.admin.UsersService;

/*
 * MyUsernamePasswordAuthenticationFilter
    attemptAuthentication
        this.getAuthenticationManager()
            ProviderManager.java
                authenticate(UsernamePasswordAuthenticationToken authRequest)
                    AbstractUserDetailsAuthenticationProvider.java
                        authenticate(Authentication authentication)
                            P155 user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
                                DaoAuthenticationProvider.java
                                    P86 loadUserByUsername
 */
public class UserSSOAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private Logger logger = LoggerFactory.getLogger(getClass());
    public static final String LOGIN_COOKIE_SEP = "[==]";
    public static final String USERNAME = "username";
    public static final String PASSWORD = "password";
    
    @Autowired
    private UsersService usersService;

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        if (!request.getMethod().equals("POST")) {
            throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        // 获取登录信息
        String username = "";
        String password = "";
        String msg = "";// 错误信息
        boolean bValidate = true;
        
        // 从Cookie中获取用户信息
        Cookie ssoLoginCookie = null;
        Cookie[] cookies = request.getCookies();
        if (cookies != null && cookies.length > 0) {
            for (Cookie cookie : cookies) {
                String cookieName = cookie.getName();
                if (cookieName.equals(Consts.COOKIE_KEY)) {
                    ssoLoginCookie = cookie;
                    String loginCookieValue;
                    try {
                        loginCookieValue = new String(Base64.getDecoder().decode(ssoLoginCookie.getValue()), "utf-8");
                        int endIndex = loginCookieValue.indexOf(LOGIN_COOKIE_SEP);
                        if (endIndex < 0) {
                            ssoLoginCookie.setValue("");
                            ssoLoginCookie.setMaxAge(0);
                            response.addCookie(ssoLoginCookie);
                            break;
                        }
                        username = new String(Base64.getDecoder().decode(loginCookieValue.substring(0, endIndex)), "utf-8");
                        password = new String(Base64.getDecoder().decode(loginCookieValue.substring(endIndex + LOGIN_COOKIE_SEP.length())), "utf-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                    }
                    break;
                }
            }
        }
        
        if ("".equals(username)) {
            bValidate = false;
            msg = "登录名不能为空！";
        }else if ("".equals(password)) {
            bValidate = false;
            msg = "密码不能为空！";
        }
        
        if(bValidate){
            //log4j日志记录登录信息
            MDC.put("ip", IPUtil.getIP(request));
            MDC.put("url", URLUtil.getURL(request));
            MDC.put("user", username);
            MDC.put("class", "org.stvd.common.security.filter.UserSSOAuthenticationFilter");
            MDC.put("method", "attemptAuthentication");
            
            Map<String, String> map = new HashMap<String, String>();
            Users user = usersService.findByPk(Users.class, username);
            if(user!=null) {
                if("T".equals(user.getEnable())) {
                    map.put("userId", username);
                    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
                    // 允许子类设置详细属性
                    setDetails(request, authRequest);
                    Authentication authentication = this.getAuthenticationManager().authenticate(authRequest);
                    if(authentication != null && authentication.isAuthenticated()){
                        
                        HttpSession session = request.getSession(false);
                        if (session != null || getAllowSessionCreation()) {
                            request.getSession().setAttribute("SPRING_SECURITY_SUCCESS_USERNAME", username);
                        }
                        
                        map.put("msg", "用户登录成功！");
                        logger.info(JsonUtils.coverToJson(map).toString());
                        
                        // 设置cookieStr的加密方式
                        String cookieUserName = null;
                        String cookiePassword = null;
                        try {
                            cookieUserName = Base64.getEncoder().encodeToString(username.getBytes("utf-8"));
                            cookiePassword = Base64.getEncoder().encodeToString(password.getBytes("utf-8"));
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        String cookieValue = null;
                        try {
                            cookieValue = Base64.getEncoder().encodeToString(
                                    (cookieUserName + LOGIN_COOKIE_SEP + cookiePassword).getBytes("utf-8"));
                        } catch (UnsupportedEncodingException e) {
                            e.printStackTrace();
                        }
                        if(ssoLoginCookie==null){
                            ssoLoginCookie = new Cookie(Consts.COOKIE_KEY, cookieValue);
                        }else{
                            ssoLoginCookie.setValue(cookieValue);
                        }
                        ssoLoginCookie.setDomain(Consts.DOMAIN_NAME);
                        ssoLoginCookie.setMaxAge(60 * 60 * 24 * 3); //有效期3天
                        ssoLoginCookie.setPath("/");
                        response.addCookie(ssoLoginCookie);
                        
                        // 运行UserDetailsService的loadUserByUsername
                        // 再次封装Authentication
                        return authentication;
                    } else {
                        msg = "用户名或密码错误";
                        map.put("msg", msg);
                        logger.error(JsonUtils.coverToJson(map).toString());
                        if (ssoLoginCookie != null) {
                            ssoLoginCookie.setValue("");
                            ssoLoginCookie.setDomain(Consts.DOMAIN_NAME);
                            ssoLoginCookie.setMaxAge(0); // 立即失效
                            ssoLoginCookie.setPath("/");
                            response.addCookie(ssoLoginCookie);
                        }
                    }
                }else {
                    msg = "此登录账号已被禁用";
                    map.put("msg", msg);
                    logger.error(JsonUtils.coverToJson(map).toString());
                }
            }else {
                msg = "当前用户不存在";
                map.put("msg", msg);
                logger.error(JsonUtils.coverToJson(map).toString());
            }
        }
        // 验证失败
        HttpSession session = request.getSession(false);
        if (session != null || getAllowSessionCreation()) {
            request.getSession().setAttribute("SPRING_SECURITY_LAST_USERNAME", username);
        }
        throw new AuthenticationServiceException(msg);
    }
}
